package com.ada.secure;

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator;
import org.bouncycastle.crypto.params.ElGamalKeyGenerationParameters;
import org.bouncycastle.crypto.params.ElGamalParameters;
import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.Security;
import java.security.SecureRandom;
import org.bouncycastle.crypto.engines.ElGamalEngine;

public class ElGamalExample {
    public static void main(String[] args) {
        Security.addProvider(new BouncyCastleProvider());

        // Generate ElGamal key pair
        AsymmetricCipherKeyPair keyPair = generateElGamalKeyPair();

        ElGamalPrivateKeyParameters privateKey = (ElGamalPrivateKeyParameters) keyPair.getPrivate();
        ElGamalPublicKeyParameters publicKey = (ElGamalPublicKeyParameters) keyPair.getPublic();

        String plainText = "Hello, ElGamal!";

        byte[] encryptedData = encryptWithPublicKey(plainText.getBytes(), publicKey);
        byte[] decryptedData = decryptWithPrivateKey(encryptedData, privateKey);

        System.out.println("Original Text: " + plainText);
        System.out.println("Encrypted Data: " + Hex.toHexString(encryptedData));
        System.out.println("Decrypted Text: " + new String(decryptedData));
    }

    // Generate ElGamal key pair
    public static AsymmetricCipherKeyPair generateElGamalKeyPair() {
        BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
                + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
                + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
                + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); // A 2048-bit prime p
        BigInteger g = BigInteger.valueOf(2); // Generator g

        ElGamalParameters elGamalParams = new ElGamalParameters(p, g);
        ElGamalKeyGenerationParameters keyGenParams = new ElGamalKeyGenerationParameters(new SecureRandom(), elGamalParams);
        ElGamalKeyPairGenerator keyPairGenerator = new ElGamalKeyPairGenerator();
        keyPairGenerator.init(keyGenParams);
        return keyPairGenerator.generateKeyPair();
    }

    // Encrypt using public key
    public static byte[] encryptWithPublicKey(byte[] data, ElGamalPublicKeyParameters publicKey) {
        ElGamalEngine engine = new ElGamalEngine();
        engine.init(true, publicKey);

        return engine.processBlock(data, 0, data.length);
    }

    // Decrypt using private key
    public static byte[] decryptWithPrivateKey(byte[] data, ElGamalPrivateKeyParameters privateKey) {
        ElGamalEngine engine = new ElGamalEngine();
        engine.init(false, privateKey);

        return engine.processBlock(data, 0, data.length);
    }
}
